package com.sxit.tdf.server.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.cms.model.v20190101.DescribeMetricListRequest;
import com.aliyuncs.cms.model.v20190101.DescribeMetricListResponse;
import com.aliyuncs.profile.DefaultProfile;
import org.springframework.scheduling.annotation.Async;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * OSS存储的工具类
 *
 * @author 橙子高
 * @date 2022/2/23 16:53
 * @describe
 */
public class OSSUtil {

  private static final String ENDPOINT = "";

  private static final String ACCESS_KEY_ID = "";

  private static final String ACCESS_KEY_SECRET = "";

  /**
   * 简单上传文件
   *
   * @param bucketName
   * @param path
   * @param fileName
   * @param fileRealPath
   * @throws IOException
   */
  public static void upLoad(String bucketName, String path, String fileName, String fileRealPath)
      throws IOException {

    // 填写Object完整路径，例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
    String objectName = path + fileName;

    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    try {
      // 删除文件或目录。如果要删除目录，目录必须为空。
      ossClient.deleteObject(bucketName, objectName);
    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  /**
   * 创建文件夹
   *
   * @param bucketName
   * @param path
   */
  @Async("AsyncTaskExecutor")
  public void createFolder(String bucketName, String path) {

    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
    try {
      PutObjectRequest putObjectRequest =
          new PutObjectRequest(
              bucketName, path, new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)));
      ossClient.putObject(putObjectRequest);
    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  /**
   * 删除文件夹
   *
   * @param bucketName
   * @param path
   */
  @Async("AsyncTaskExecutor")
  public void deleteFolder(String bucketName, String path) {

    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
    try {
      ossClient.deleteObject(bucketName, path);

    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  public void deleteBucket(String bucketName) {
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    try {
      // 删除存储空间。
      ossClient.deleteBucket(bucketName);
    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  /**
   * 单一删除
   *
   * @param bucketName
   * @param path
   * @param fileName
   */
  @Async("AsyncTaskExecutor")
  public void deleteFile(String bucketName, String path, String fileName) {
    // 填写Object完整路径，例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
    String objectName = path + fileName;

    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    try {
      // 填写字符串。
      String content = "Hello OSS";

      ossClient.deleteObject(bucketName, objectName);

    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  /**
   * 创建筒 这里的意思就是之前思维导图里面的最文件夹
   *
   * @param bucketName
   */
  @Async("AsyncTaskExecutor")
  public void createBucket(String bucketName) {

    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    try {

      CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
      createBucketRequest.setStorageClass(StorageClass.Standard);
      createBucketRequest.setCannedACL(CannedAccessControlList.PublicReadWrite);

      ossClient.createBucket(createBucketRequest);
      serCors(bucketName);
    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  private void serCors(String bucketCode) {
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    SetBucketCORSRequest request = new SetBucketCORSRequest(bucketCode);

    // 跨域资源共享规则的容器，每个存储空间最多允许10条规则。
    ArrayList<SetBucketCORSRequest.CORSRule> putCorsRules =
        new ArrayList<SetBucketCORSRequest.CORSRule>();

    SetBucketCORSRequest.CORSRule corRule = new SetBucketCORSRequest.CORSRule();

    ArrayList<String> allowedOrigin = new ArrayList<String>();
    // 指定允许跨域请求的来源。
    allowedOrigin.add("*");

    ArrayList<String> allowedMethod = new ArrayList<String>();
    // 指定允许的跨域请求方法(GET/PUT/DELETE/POST/HEAD)。
    allowedMethod.add("GET");

    ArrayList<String> allowedHeader = new ArrayList<String>();
    // 是否允许预取指令（OPTIONS）中Access-Control-Request-Headers头中指定的Header。
    allowedHeader.add("*");

    ArrayList<String> exposedHeader = new ArrayList<String>();
    // 指定允许用户从应用程序中访问的响应头。
    exposedHeader.add("Etag");
    // AllowedOrigins和AllowedMethods最多支持一个星号（*）通配符。星号（*）表示允许所有的域来源或者操作。
    corRule.setAllowedMethods(allowedMethod);
    corRule.setAllowedOrigins(allowedOrigin);
    // AllowedHeaders和ExposeHeaders不支持通配符。
    corRule.setAllowedHeaders(allowedHeader);
    corRule.setExposeHeaders(exposedHeader);
    // 指定浏览器对特定资源的预取（OPTIONS）请求返回结果的缓存时间，单位为秒。
    corRule.setMaxAgeSeconds(10);

    // 最多允许10条规则。
    putCorsRules.add(corRule);
    // 已存在的规则将被覆盖。
    request.setCorsRules(putCorsRules);
    // 指定是否返回Vary: Origin头。指定为TRUE，表示不管发送的是否为跨域请求或跨域请求是否成功，均会返回Vary:
    // Origin头。指定为False，表示任何情况下都不会返回Vary: Origin头。
    // request.setResponseVary(Boolean.TRUE);
    ossClient.setBucketCORS(request);
  }

  /** 批量删除 */
  public void deleteFiles(String bucketName, List<String> files) {
    // 删除文件。
    // 填写需要删除的多个文件完整路径。文件完整路径中不能包含Bucket名称。
    List<String> keys = new ArrayList<>();
    keys.addAll(files);
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    DeleteObjectsResult deleteObjectsResult =
        ossClient.deleteObjects(
            new DeleteObjectsRequest(bucketName).withKeys(keys).withEncodingType("url"));
    List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
    try {
      for (String obj : deletedObjects) {
        String deleteObj = URLDecoder.decode(obj, "UTF-8");
        System.out.println(deleteObj);
      }
    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  @Async("AsyncTaskExecutor")
  public void uploadFile(String bucketName, String path, String fileName, byte[] fileBytes) {

    // 填写Object完整路径，例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
    String objectName = path + fileName;
    //    byte[] bytes = FileUtil.readFileByBytes(fileRealPath);
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

    try {

      // 创建PutObjectRequest对象。
      PutObjectRequest putObjectRequest =
          new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(fileBytes));

      // 上传字符串。
      ossClient.putObject(putObjectRequest);
    } catch (OSSException oe) {
      System.out.println(
          "Caught an OSSException, which means your request made it to OSS, "
              + "but was rejected with an error response for some reason.");
      System.out.println("Error Message:" + oe.getErrorMessage());
      System.out.println("Error Code:" + oe.getErrorCode());
      System.out.println("Request ID:" + oe.getRequestId());
      System.out.println("Host ID:" + oe.getHostId());
    } catch (ClientException ce) {
      System.out.println(
          "Caught an ClientException, which means the client encountered "
              + "a serious internal problem while trying to communicate with OSS, "
              + "such as not being able to access the network.");
      System.out.println("Error Message:" + ce.getMessage());
    } finally {
      if (ossClient != null) {
        ossClient.shutdown();
      }
    }
  }

  public ArrayList<String> getMessage() throws com.aliyuncs.exceptions.ClientException {
    DefaultProfile profile =
        DefaultProfile.getProfile("cn-beijing", ACCESS_KEY_ID, ACCESS_KEY_SECRET);
    IAcsClient client = new DefaultAcsClient(profile);

    DescribeMetricListRequest request = new DescribeMetricListRequest();
    request.setNamespace("acs_oss_dashboard");
    // 获取前一天的数据
    Date date = DateUtil.parse(DateUtil.date().toDateStr());
    request.setEndTime(date.toString());
    request.setStartTime(DateUtil.offsetDay(date, -15).toString());

    request.setMetricName("UserInternetSend");
    Class<DescribeMetricListResponse> responseClass = request.getResponseClass();
    //        request.setMetricName("UserInternetRecv");

    System.out.println(request.getResponseClass());
    DescribeMetricListResponse acsResponse = client.getAcsResponse(request);
    List<AccResponseDataPoint> list =
        JSON.parseArray(acsResponse.getDatapoints(), AccResponseDataPoint.class);

    ArrayList<String> result = new ArrayList<>();

    list.forEach(
        item -> {
          result.add(NumberUtil.roundStr(item.getValue() % 1024.0, 2));
        });
    return result;
  }
}
